/* bsp_config.c */
#include "bsp_config.h"
#include "hal_lpuart.h"

/*!
# KE18F的时钟系统包含：
 - System PLL (SPLL) can use the SOSC or FIRC as input source.
 - Slow IRC (SIRC)
 - Fast IRC (FIRC)
 - System OSC (SOSC)
*/

void CLK_Config_HSRUN_IRC48M_150M(void);
void CLK_Config_HSRUN_OSC8M_160M(void);
void CLK_Config_HSRUN_OSC12M_168M(void);


void BSP_InitSystem(void)
{
    CLOCK_FastIRCConfig_T clockFastIrcConfigStruct;

    /* Enable all the PORT. */
    PCC->CLKCFG[PCC_PORTA_INDEX] |= PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTB_INDEX] |= PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTC_INDEX] |= PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTD_INDEX] |= PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTE_INDEX] |= PCC_CLKCFG_CGC_MASK;

    PCC->CLKCFG[PCC_DMA0_INDEX] |= PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_DMAMUX0_INDEX] |= PCC_CLKCFG_CGC_MASK;

#if CLOCK_SETUP==1
    CLK_Config_HSRUN_IRC48M_150M();
#elif CLOCK_SETUP==2
    CLK_Config_HSRUN_OSC8M_160M();
#elif CLOCK_SETUP==3
    CLK_Config_HSRUN_OSC12M_168M();
#endif /* CLOCK_SETUP */

    clockFastIrcConfigStruct.ClockRange = eCLOCK_FastIRCRange_48MHz;
    clockFastIrcConfigStruct.AsyncClkOutputDiv1 = 0x3; /* div = 4. */
    clockFastIrcConfigStruct.AsyncClkOutputDiv2 = 0x3; /* div = 4. */
    clockFastIrcConfigStruct.enClkOnVLPxMode = true;
    clockFastIrcConfigStruct.enClkOnStopMode = true;
    CLOCK_ConfigFastIRC(&clockFastIrcConfigStruct);

    SystemCoreClockUpdate();
}

void CLK_Config_HSRUN_OSC12M_168M(void)
{
    /*
     * STEP1: Enable and enter into the HSRUN.
     */
    SMC->PMPROT = SMC_PMPROT_AHSRUN_MASK | SMC_PMPROT_AVLP_MASK; /* HSRUN and VLPR are allowed. */
    SMC->PMCTRL = SMC_PMCTRL_RUNM(3);    /* High speed run. */
    /* Wait till the system transfer to HSRUN. */
    while(SMC->PMSTAT != 0x80)
    {}

    /*
     * STEP2: Enable the System OSC. External OSC - 12MHz
     */
    /* Configure the Core/Bus clock when System OSC is used as the SCG's main output clock. */
    SCG->SOSCCSR &= ~SCG_SOSCCSR_SOSCEN_MASK; /* Disable the System OSC before configuring it. */
    SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV2(0x2)  /* BusClk = CoreClk/2, for the standalone clock source.*/
                 | SCG_SOSCDIV_SOSCDIV1(0x1); /* CoreClk = OSC/1, for the standalone clock source. */
    SCG->SOSCCFG = SCG_SOSCCFG_RANGE(0x3) /* High frequency range selected for the crystal oscillator of 8 Mhz to 32 Mhz. */
                 | SCG_SOSCCFG_HGO_MASK   /* Configure crystal oscillator for high-gain operation. */
                 | SCG_SOSCCFG_EREFS_MASK; /* Internal crystal oscillator of OSC requested. */
    SCG->SOSCCSR = SCG_SOSCCSR_SOSCERR_MASK /* Clear error flag. */
                 | SCG_SOSCCSR_SOSCLPEN_MASK /* System OSC is enabled in VLP modes. */
                 | SCG_SOSCCSR_SOSCSTEN_MASK /* System OSC is enabled in Stop modes if SOSCEN=1. */
                 | SCG_SOSCCSR_SOSCEN_MASK;  /* System OSC is enabled. */
    /* Wait till the SOSC output is available. */
    while (SCG_SOSCCSR_SOSCVLD_MASK != (SCG_SOSCCSR_SOSCVLD_MASK & SCG->SOSCCSR))
    {}

    /*
     * STEP3: Prepare the SPLL with OSC before switching to the main clock.
     */
    /* PLL clock source: System OSC. PLL input divide factor: 1, Multiple factor: 40
     * SOSC = 12MHz, VCO = (12MHz / 1) * 28 = 336MHz, CoreClk = 336MHz / 2 = 168MHz
     */
    /* SCG->SPLLCFG[SOURCE] = 0 */ /* Configures the input clock source for the System PLL as System OSC. */
    SCG->SPLLCFG = SCG_SPLLCFG_PREDIV(0x0)   /* Pre-divide factor: 1. */
                 | SCG_SPLLCFG_MULT(0xC); /* Multiple factor: 28. */
    /* Configure the Core/Bus clock when PLL is used as the SCG's main output clock. */
    SCG->SPLLDIV = SCG_SPLLDIV_SPLLDIV1(0x3) /* Divider for async PLLDIV1_CLK: 4, 168MHz/4 = 42MHz. */
                 | SCG_SPLLDIV_SPLLDIV2(0x2);/* Divider for async PLLDIV2_CLK: 2, 168MHz/2 = 84MHz. */
    SCG->SPLLCSR = SCG_SPLLCSR_SPLLERR_MASK  /* Clear error flag. */
                 | SCG_SPLLCSR_SPLLSTEN_MASK /* System PLL is enabled in Stop modes */
                 | SCG_SPLLCSR_SPLLEN_MASK;  /* System PLL is enabled. */
    /* Wait till the PLL output is available. */
    while (SCG_SPLLCSR_SPLLVLD_MASK != (SCG_SPLLCSR_SPLLVLD_MASK & SCG->SPLLCSR))
    {}

    /*
     * STEP4: Switch the main clock to be with SPLL.
     */
    /* Config Core/Bus/Flash clock in HSRUN. */
    SCG->HCCR = SCG_HCCR_SCS(0x6) /* Selects the System PLL generating the system clock in HSRUN mode. */
              | SCG_HCCR_DIVCORE(0x0)  /* CoreCLk = PLL/2/(1) = 168MHz. */
              | SCG_HCCR_DIVBUS(0x1)   /* BusClk = CoreClk/(2) = 84MHz. */
              | SCG_HCCR_DIVSLOW(0x7); /* FlashClk = CoreClk/(8) = 21MHz. */
    /* Wait while the SPLL is taking the charge of the system clock. */
    while (SCG_SPLLCSR_SPLLSEL_MASK != (SCG->SPLLCSR & SCG_SPLLCSR_SPLLSEL_MASK))
    {}
}

void CLK_Config_HSRUN_OSC8M_160M(void)
{
    /*
     * STEP1: Enable and enter into the HSRUN.
     */
    SMC->PMPROT = SMC_PMPROT_AHSRUN_MASK | SMC_PMPROT_AVLP_MASK; /* HSRUN and VLPR are allowed. */
    SMC->PMCTRL = SMC_PMCTRL_RUNM(3);    /* High speed run. */
    /* Wait till the system transfer to HSRUN. */
    while(SMC->PMSTAT != 0x80)
    {}

    /*
     * STEP2: Enable the System OSC. External OSC - 8MHz
     */
    /* Configure the Core/Bus clock when System OSC is used as the SCG's main output clock. */
    SCG->SOSCCSR &= ~SCG_SOSCCSR_SOSCEN_MASK; /* Disable the System OSC before configuring it. */
    SCG->SOSCDIV = SCG_SOSCDIV_SOSCDIV2(0x2)  /* BusClk = OSC/2, for the standalone clock source.*/
                 | SCG_SOSCDIV_SOSCDIV1(0x1); /* CoreClk = OSC/1, for the standalone clock source. */
    SCG->SOSCCFG = SCG_SOSCCFG_RANGE(0x3) /* High frequency range selected for the crystal oscillator of 8 Mhz to 32 Mhz. */
                 | SCG_SOSCCFG_HGO_MASK   /* Configure crystal oscillator for high-gain operation. */
                 | SCG_SOSCCFG_EREFS_MASK; /* Internal crystal oscillator of OSC requested. */
    SCG->SOSCCSR = SCG_SOSCCSR_SOSCERR_MASK /* Clear error flag. */
                 | SCG_SOSCCSR_SOSCLPEN_MASK /* System OSC is enabled in VLP modes. */
                 | SCG_SOSCCSR_SOSCSTEN_MASK /* System OSC is enabled in Stop modes if SOSCEN=1. */
                 | SCG_SOSCCSR_SOSCEN_MASK;  /* System OSC is enabled. */
    /* Wait till the SOSC output is available. */
    while (SCG_SOSCCSR_SOSCVLD_MASK != (SCG_SOSCCSR_SOSCVLD_MASK & SCG->SOSCCSR))
    {}

    /*
     * STEP3: Prepare the SPLL with OSC before switching to the main clock.
     */
    /* PLL clock source: System OSC. PLL input divide factor: 1, Multiple factor: 40
     * SOSC = 8MHz, VCO = (8MHz / 1) * 40 = 320MHz, CoreClk = 320MHz / 2 = 160MHz
     */
    /* SCG->SPLLCFG[SOURCE] = 0 */ /* Configures the input clock source for the System PLL as System OSC. */
    SCG->SPLLCFG = SCG_SPLLCFG_PREDIV(0x0)   /* Pre-divide factor: 1. */
                 | SCG_SPLLCFG_MULT(0x18); /* Multiple factor: 40 */
    /* Configure the Core/Bus clock when PLL is used as the SCG's main output clock. */
    SCG->SPLLDIV = SCG_SPLLDIV_SPLLDIV2(0x3) /* Divider for System Clock: 4, 320MHz/4 = 80MHz. */
                 | SCG_SPLLDIV_SPLLDIV1(0x2);/* Divider for Core Clock: 2, 320MHz/2 = 160MHz. */
    SCG->SPLLCSR = SCG_SPLLCSR_SPLLERR_MASK  /* Clear error flag. */
                 | SCG_SPLLCSR_SPLLSTEN_MASK /* System PLL is enabled in Stop modes */
                 | SCG_SPLLCSR_SPLLEN_MASK;  /* System PLL is enabled. */
    /* Wait till the PLL output is available. */
    while (SCG_SPLLCSR_SPLLVLD_MASK != (SCG_SPLLCSR_SPLLVLD_MASK & SCG->SPLLCSR))
    {}

    /*
     * STEP4: Switch the main clock to be with SPLL.
     */
    /* Config Core/Bus/Flash clock in HSRUN. */
    SCG->HCCR = SCG_HCCR_SCS(0x6) /* Selects the System PLL generating the system clock in HSRUN mode. */
              | SCG_HCCR_DIVCORE(0x0)  /* CoreCLk = PLL/2/(1) = 160MHz. */
              | SCG_HCCR_DIVBUS(0x1)   /* BusClk = CoreClk/(2) = 80MHz. */
              | SCG_HCCR_DIVSLOW(0x7); /* FlashClk = CoreClk/(8) = 20MHz. */
    /* Wait while the SPLL is taking the charge of the system clock. */
    while (SCG_SPLLCSR_SPLLSEL_MASK != (SCG->SPLLCSR & SCG_SPLLCSR_SPLLSEL_MASK))
    {}
}

void CLK_Config_HSRUN_IRC48M_150M(void)
{
    /*
     * STEP1: Enable and enter into the HSRUN.
     */
    SMC->PMPROT = SMC_PMPROT_AHSRUN_MASK | SMC_PMPROT_AVLP_MASK; /* HSRUN and VLPR are allowed. */
    SMC->PMCTRL = SMC_PMCTRL_RUNM(3); /* High speed run. */
    /* Wait till the system transfer to HSRUN. */
    while(SMC->PMSTAT != 0x80)
    {}

    /*
     * STEP2: Prepare the SPLL with FIRC before switching to the main clock.
     */
    /* Configure the Core/Bus Clock when PLL is used as SCG's main clock output.
     * FIRC = 48MHz, PLL VCO = (FIRC / (4)) * (25) = 300MHz,
     * Core Clock = PLL VCO / 2 / (1) = 150MHz,
     * Bus Clock  = Core Clock / (2) = 75MHz
     */
    SCG->SPLLDIV = SCG_SPLLDIV_SPLLDIV1(2)   /* For SPLLDIV1 = PLL/2/(2) = 150MHz/(2) = 75MHz. divider=2, used for FTM only. */
                 | SCG_SPLLDIV_SPLLDIV2(2);  /* For SPLLDIV2 = PLL/2/(2) = 150MHz/(2) = 75MHz. divider=2, used for other peripherals. */
    SCG->SPLLCFG = SCG_SPLLCFG_SOURCE_MASK   /* Source: 0-System OSC; 1-Firc48M */
                 | SCG_SPLLCFG_PREDIV(3)  /* PLL prediv factor = 4 */
                 | SCG_SPLLCFG_MULT(9);   /* PLL mult factor = 25 */
    SCG->SPLLCSR = SCG_SPLLCSR_SPLLEN_MASK; /* Enable the PLL */
    /* Waiting until SPLL output clock is valid. */
    while(SCG_SPLLCSR_SPLLVLD_MASK != (SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK))
    {}

    /*
     * STEP3: Switch the main clock to be with SPLL.
     */
    /* Configure Core/Bus/Flash clock in HSRUN. */
    SCG->HCCR = SCG_HCCR_SCS(0x6) /* Selects the System PLL generating the system clock in HSRUN mode. */
              | SCG_HCCR_DIVCORE(0x0)  /* CoreCLk = PLL/2/(1) = 150MHz. */
              | SCG_HCCR_DIVBUS(0x1)   /* BusClk = CoreClk/(2) = 75MHz. */
              | SCG_HCCR_DIVSLOW(0x5); /* FlashClk = CoreClk/(6) = 25MHz. */
    /* Wait while the SPLL is taking the charge of the system clock. */
    while (SCG_SPLLCSR_SPLLSEL_MASK != (SCG->SPLLCSR & SCG_SPLLCSR_SPLLSEL_MASK))
    {}
}

void BSP_InitLpuartForDebug(void)
{
    PCC->CLKCFG[PCC_LPUART0_INDEX] = PCC_CLKCFG_CGC_MASK | PCC_CLKCFG_PCS(6); /* BSP_CLK_SPLLDIV2_HZ. */

#ifdef BOARD_KE18F_NANO
    PORTA->PCR[10] = PORT_PCR_MUX(3); /* LPUART0_RX. */
    PORTA->PCR[11] = PORT_PCR_MUX(3); /* LPUART0_TX */
#else
    PORTB->PCR[0] = PORT_PCR_MUX(2); /* LPUART0_RX. */
    PORTB->PCR[1] = PORT_PCR_MUX(2); /* LPUART0_TX. */
    /* Configure PCC to enable clock for LPUART0. */
#endif
}

void BSP_InitStdioLPUART(uint32_t baudrate)
{
#if 0
    /* LPUART0 */
    /* Configure pins' mux. */
    //PCC->CLKCFG[PCC_PORTB_INDEX] = PCC_CLKCFG_CGC_MASK;
    PORTB->PCR[0] = PORT_PCR_MUX(2); /* LPUART0_RX. */
    PORTB->PCR[1] = PORT_PCR_MUX(2); /* LPUART0_TX. */
    /* Configure PCC to enable clock for LPUART0. */
    PCC->CLKCFG[PCC_LPUART0_INDEX] = PCC_CLKCFG_CGC_MASK | PCC_CLKCFG_PCS(6); /* BSP_CLK_SPLLDIV2_HZ. */
#endif
    BSP_InitLpuartForDebug();
    /* Configure LPUART module. */
    LPUART_HAL_Reset(BSP_LPUART_DEBUG_PORT);
    LPUART_HAL_SetBaudrate(BSP_LPUART_DEBUG_PORT, BSP_CLK_SPLLDIV2_HZ, baudrate);
    LPUART_HAL_EnableTx(BSP_LPUART_DEBUG_PORT, true);
    LPUART_HAL_EnableRx(BSP_LPUART_DEBUG_PORT, true);

}

void BSP_InitWs2812bGpio(void)
{
    PCC->CLKCFG[PCC_PORTC_INDEX] = PCC_CLKCFG_CGC_MASK;
    PORTC->PCR[2] = PORT_PCR_MUX(1);
    PORTC->PCR[3] = PORT_PCR_MUX(1);
}

void BSP_InitKeyGpio(void)
{
    PCC->CLKCFG[PCC_PORTC_INDEX] = PCC_CLKCFG_CGC_MASK;
    PORTC->PCR[5] = PORT_PCR_MUX(1);
}

void BSP_InitLpuartForBLE(void)
{
    PCC->CLKCFG[PCC_LPUART1_INDEX] = PCC_CLKCFG_CGC_MASK | PCC_CLKCFG_PCS(6); /* BSP_CLK_SPLLDIV2_HZ. */

    /* Enable the pin mux for BLE. */
    PORTC->PCR[6] = PORT_PCR_MUX(2); /* LPUART1_RX. */
    PORTC->PCR[7] = PORT_PCR_MUX(2); /* LPUART1_TX. */
}

void BSP_InitGpioForBLE(void)
{
    PCC->CLKCFG[PCC_PORTA_INDEX] = PCC_CLKCFG_CGC_MASK;
    PORTA->PCR[12] = PORT_PCR_MUX(1);
    PORTA->PCR[13] = PORT_PCR_MUX(1);
}

void BSP_InitAdcBatterySensor(void)
{
    PCC->CLKCFG[PCC_ADC0_INDEX] = 0; /* Disable the clock before change any clock source. */
    PCC->CLKCFG[PCC_ADC0_INDEX] = PCC_CLKCFG_CGC_MASK
                                | PCC_CLKCFG_PCS(CLOCK_RootClockSourceSel_FastIRC);
    PORTC->PCR[0] = PORT_PCR_MUX(0); /* ADC0_SE8. */
}

/* 配置作为控制速度的FTM模块及控制方向的GPIO引脚 */
void BSP_InitMotorTurn(void)
{
    /* Enable clock. */
    PCC->CLKCFG[PCC_PORTB_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTE_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTD_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_FLEXTMR0_INDEX] = PCC_CLKCFG_CGC_MASK; /* FTM0. */

    /* MOTOR_ID_A. */
    PORTE->PCR[8] = PORT_PCR_MUX(1); /* BSP_GPIO_MOTOR_A_IN1 */
    PORTE->PCR[9] = PORT_PCR_MUX(1); /* BSP_GPIO_MOTOR_A_IN2 */
    PORTD->PCR[16] = PORT_PCR_MUX(2); /* BSP_FTM_MOTOR_A */

    /* MOTOR_ID_B. */
    PORTB->PCR[5] = PORT_PCR_MUX(1); /* BSP_GPIO_MOTOR_B_IN1 */
    PORTB->PCR[4] = PORT_PCR_MUX(1); /* BSP_GPIO_MOTOR_B_IN2 */
    /* BSP_FTM_MOTOR_B */
    PORTD->PCR[15] = PORT_PCR_MUX(2) | PORT_PCR_DSE_MASK;

    /* Stand by. */
    PORTD->PCR[5] = PORT_PCR_MUX(1);

}

/* 配置作为编码器的FTM模块 */
void BSP_InitMotorQuadDecoder(void)
{
    PCC->CLKCFG[PCC_PORTE_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTB_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_FLEXTMR1_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_FLEXTMR2_INDEX] = PCC_CLKCFG_CGC_MASK;

    /* MOTOR_ID_A. */
    PORTE->PCR[5] = PORT_PCR_MUX(3); /* FTM2_QD_PHA */
    PORTE->PCR[4] = PORT_PCR_MUX(3); /* FTM2_QD_PHB */

    /* MOTOR_ID_B. */
    PORTB->PCR[3] = PORT_PCR_MUX(4); /* FTM1_QD_PHA */
    PORTB->PCR[2] = PORT_PCR_MUX(4); /* FTM1_QD_PHB */
}

/* 配置作为解调RC接收机输出信号的的FTM模块的GPIO引脚 */
void BSP_InitRcDemodulator(void)
{
    /* Enable clock. */
    PCC->CLKCFG[PCC_PORTB_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTE_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTD_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_FLEXTMR3_INDEX] = PCC_CLKCFG_CGC_MASK; /* FTM3. */

    /* 油门信号 */
    PORTE->PCR[2] = PORT_PCR_MUX(4); /* BSP_GPIO_RC_SPEED_CAPTURE_CHANNEL_NUM */

    /* 转向信号 */
    PORTE->PCR[6] = PORT_PCR_MUX(4); /* BSP_GPIO_RC_TURN_CAPTURE_CHANNEL_NUM */
    
    PORTE->DFWR = 1;
    PORTE->DFCR = 1;
    PORTE->DFER = 0x000000C0;
}

/* 使用NANO板子上RF端口上的SPI信号
 * PTB1 - LPSPI0_SOUT(MOSI)
 * PTE1 - LPSPI0_SIN (MISO)
 * PTE0 - LPSPI0_CLK
 * PTB0 - LPSPI0_CS
 */
void BSP_InitExt_SDCard(void)
{
    /* clocks. */
    PCC->CLKCFG[PCC_PORTB_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_PORTE_INDEX] = PCC_CLKCFG_CGC_MASK;
    PCC->CLKCFG[PCC_LPSPI0_INDEX] = PCC_CLKCFG_CGC_MASK | PCC_CLKCFG_PCS(6U); /* System PLL. */
    
    /* pin mux. */
    PORTB->PCR[1]  = PORT_PCR_MUX(3); /* LPSPI0_SOUT. */
    PORTE->PCR[1]  = PORT_PCR_MUX(2) | PORT_PCR_PE_MASK | PORT_PCR_PS_MASK;  /* SPI_SIN. */
    PORTE->PCR[0]  = PORT_PCR_MUX(2);  /* LPSPI0_CLK. */
    PORTB->PCR[0]  = PORT_PCR_MUX(1);  /* LPSPI0_CS, GPIO. */
}

/* EOF. */
